/*
 * Galaxium Messenger
 * Copyright (C) 2005-2007 Ben Motmans <ben.motmans@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;

using Anculus.Core;
using Galaxium.Core;

namespace Galaxium.Gui
{
	public delegate IconType RescaleIconTypeHandler<IconType> (IconType icon, IIconSize size);
	
	internal class IconTheme<IconType>
	{
		private Dictionary<string, Dictionary<IIconSize, IconType>> _icons;
		private Dictionary<string, Dictionary<IIconSize, IconExtension<IconType>>> _lazyIcons;
		private RescaleIconTypeHandler<IconType> _rescaleHandler;

		internal IconTheme (RescaleIconTypeHandler<IconType> rescaleHandler)
		{
			this._icons = new Dictionary<string, Dictionary<IIconSize, IconType>> ();
			this._lazyIcons = new Dictionary<string, Dictionary<IIconSize, IconExtension<IconType>>> ();
			this._rescaleHandler = rescaleHandler;
		}

		internal IconType GetIcon (string name)
		{
			return GetIcon (name, IconSizes.Other);
		}

		internal IconType GetIcon (string name, IIconSize iconSize)
		{
			if (_lazyIcons.ContainsKey (name))
			{
				Dictionary<IIconSize, IconExtension<IconType>> iconset = _lazyIcons[name];
				
				if (iconset.ContainsKey (iconSize))
				{
					IconExtension<IconType> ext = iconset[iconSize];
					AddIcon (ext.Identifier, ext.IconSize, ext.GetIcon ());
				}
				else
				{
					IIconSize matchingSize = GetMatchingSize (iconSize, iconset.Keys);
					IconExtension<IconType> ext = iconset[matchingSize];
					AddIcon (ext.Identifier, ext.IconSize, ext.GetIcon ());
				}
			}
			
			if (_icons.ContainsKey (name)) 
			{
				Dictionary<IIconSize, IconType> iconset = _icons[name];
				
				if (iconset.ContainsKey (iconSize))
				{
					return iconset[iconSize];
				}
				else
				{
					IIconSize matchingSize = GetMatchingSize (iconSize, iconset.Keys);
					
					if (matchingSize.Equals (IconSizes.Other))
					{
						return iconset[matchingSize];
					}
					else
					{
						return _rescaleHandler (iconset[matchingSize], iconSize);
					}
				}
			}
			else
			{
				Log.Error("Icon ["+name+"] not in list.");
			}
			
			return default (IconType);
		}

		internal IIconSize GetMatchingSize (IIconSize size, IEnumerable<IIconSize> sizes)
		{
			IIconSize selected = null;
			int diff = int.MaxValue;

			//get the closest icon that is bigger then the required size
			foreach (IIconSize s in sizes) {
				if (s.Size > size.Size) {
					int curdiff = Math.Abs (s.Size - size.Size);
					if (curdiff < diff) {
						selected = s;
						diff = curdiff;
					}
				}
			}

			//get the closest icon that is smaller then the required size
			diff = int.MaxValue;
			if (selected == null) {
				foreach (IIconSize s in sizes) {
					if (s.Size < size.Size) {
						int curdiff = Math.Abs (s.Size - size.Size);
						if (curdiff < diff) {
							selected = s;
							diff = curdiff;
						}
					}
				}
			}
			return selected;
		}

		public void AddIcon (string name, IIconSize iconSize, IconType icon)
		{
			if (_icons.ContainsKey (name))
			{
				Dictionary<IIconSize, IconType> iconset = _icons[name];
				
				if (iconset.ContainsKey (iconSize))
					iconset[iconSize] = icon;
				else
					iconset.Add (iconSize, icon);
			}
			else
			{
				Dictionary<IIconSize, IconType> iconset = new Dictionary<IIconSize, IconType> ();
				
				iconset.Add (iconSize, icon);
				
				_icons.Add (name, iconset);
			}
		}
		
		internal void AddIcon (IconExtension<IconType> ext, bool ignoreLazyLoad)
		{
			if (ext.LazyLoad && !ignoreLazyLoad)
			{
				if (!_lazyIcons.ContainsKey (ext.Identifier))
					_lazyIcons.Add (ext.Identifier, new Dictionary<IIconSize, IconExtension<IconType>> ());
				
				Dictionary<IIconSize, IconExtension<IconType>> iconset = _lazyIcons[ext.Identifier];
				
				if (iconset.ContainsKey (ext.IconSize))
					iconset[ext.IconSize] = ext;
				else
					iconset.Add (ext.IconSize, ext);
			}
			else
			{
				IconType icon = ext.GetIcon ();
				
				if (icon != null)
					AddIcon (ext.Identifier, ext.IconSize, icon);
				else
					Log.Warn ("Unable to create Icon. (name: {0})", ext.Resource);
			}
		}

		public bool IconExists (string name)
		{
			return _icons.ContainsKey (name) || _lazyIcons.ContainsKey (name);
		}

		public IEnumerable<string> Names
		{
			get { return _icons.Keys; }
		}
	}
}
